package com.songqintuan.common.dal.ibatis.dao;

import java.io.Serializable;


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import org.springframework.util.Assert;

import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.mapping.sql.stat.StaticSql;
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
import com.songqintuan.common.bean.Page;
/** 
#  * IBatis Dao的泛型基类. 
#  * 继承于Spring的SqlMapClientDaoSupport,提供分页函数和若干便捷查询方法，并对返回值作了泛型类型转换. 
#  */ 
@SuppressWarnings("unchecked")
public class IBatisGenericDao<T, PK extends Serializable> extends SqlMapClientDaoSupport {
	public static final String POSTFIX_INSERT = ".insert";
	   
	public static final String POSTFIX_UPDATE = ".update";
	
	public static final String POSTFIX_UPDATEBYMAP = ".updateByMap";
	
	public static final String POSTFIX_UPDATEBYIDSMAP = ".updateByIdsMap";
	 
	public static final String POSTFIX_DELETE = ".delete"; 
	 
	public static final String POSTFIX_DELETE_PRIAMARYKEY = ".deleteByPrimaryKey";

	public static final String POSTFIX_DELETEBYIDS = ".deleteByIds";
	
	public static final String POSTFIX_DELETEBYIDSMAP = ".deleteByIdsMap";
	
	public static final String POSTFIX_DELETEBYMAP = ".deleteByMap";
	
	public static final String POSTFIX_SELECTBYID = ".selectById";//SQL语句只写 select * from table   ;where 语句动态生成
	
	public static final String POSTFIX_SELECTBYIDS = ".selectByIds";
	 
	public static final String POSTFIX_SELECTMAP = ".selectByMap";
	 
	public static final String POSTFIX_SELECTSQL = ".selectBySql";
	 
	public static final String POSTFIX_COUNT = ".count";
	
	public static final String POSTFIX_COUNTLIKEBYMAP = ".countLikeByMap";
	 
	/** 
	 * 根据ID获取对象 
	 *  
	 * @throws BaseException 
	 * @throws SQLException  
	 */  
	public T findById(Class<T> entityClass, PK id) throws Exception, SQLException {  
	 
	 T o = (T) getSqlMapClient().queryForObject(entityClass.getName() + POSTFIX_SELECTBYID, id);  
	 if (o == null)  
	  throw new Exception(Exception.class + "未找到实体: " + id);  
	 return o;  
	}  
	/** 
	     * 根据条件查询结果 
	      *  
	      * @param properties 
	      *            查询条件名 
	      * @param propertyValues 
	     *            查询条件值 
	      * @return 
	      */
	public List<T> findByPropertiesValues(Class<T> entityClass,String[] properties, Object[] propertyValues, String orderBy, String order) throws Exception, SQLException {  
		 Map<String, Object> map = new HashMap<String, Object>();  
		         for (int i = 0; i < properties.length; i++) {  
		             map.put(properties[i], propertyValues[i]);  
		         }  
		         if (orderBy != null) {  
		             map.put("orderBy", orderBy);  
		             map.put("order", order);  
		         }
		 return this.find(entityClass, map);
	}
	
	/** 
	#      * 根据ids获取实体列表 
	#      *  
	#      * @param ids 
	#      * @return 
	#      */  
    @SuppressWarnings("unchecked")
	public List<T> findByIds(Class<T> entityClass,List<PK> ids)throws Exception, SQLException {  
	   return (List<T>) getSqlMapClient().queryForList(entityClass.getName() + POSTFIX_SELECTBYIDS, ids);  
	} 
	 
	/** 
	 * 获取全部对象 
	 * @throws SQLException  
	 */  
	public List<T> getAll(Class<T> entityClass) throws SQLException {  
		return getSqlMapClient().queryForList(entityClass.getName() + POSTFIX_SELECTBYID, null);  
	}  
	 
	/** 
	 * 新增对象 
	 * @throws SQLException  
	 */  
	public void insert(T o) throws SQLException { 
		
	 getSqlMapClient().insert(o.getClass().getName() + POSTFIX_INSERT, o);  
	}  
	 
	/** 
	 * 保存对象 
	 * @throws SQLException  
	 */  
	public int update(T o) throws SQLException {  
	 return getSqlMapClient().update(o.getClass().getName() + POSTFIX_UPDATE, o);  
	}  
	 
	/** 
	 * 删除对象 
	 * @throws SQLException  
	 */  
	public int delete(T o) throws SQLException {  
	 return getSqlMapClient().delete(o.getClass().getName() + POSTFIX_DELETE, o);  
	}  
	 
	public void deleteByIds(Class<T> entityClass, List<PK> ids) throws Exception {  
		getSqlMapClient().delete(entityClass.getName() + POSTFIX_DELETEBYIDS, ids);  
	} 
	/** 
	 * 根据ID删除对象 
	 * @throws SQLException  
	 */  
	public int deleteById(Class<T> entityClass, Serializable id) throws SQLException {  
	 return getSqlMapClient().delete(entityClass.getName() + POSTFIX_DELETE_PRIAMARYKEY, id);  
	}  
	 
	/** 
	 * map查询. 
	 *  
	 * @param map 
	 *            包含各种属性的查询 
	 * @throws SQLException  
	 */  
	public List<T> find(Class<T> entityClass, Map<String, Object> map) throws SQLException {  
	 if (map == null)  
	  return this.getSqlMapClient().queryForList(entityClass.getName() + POSTFIX_SELECTBYID, null);  
	 else {  
	  map.put("findBy", "True");  
	  return this.getSqlMapClient()  
	    .queryForList(entityClass.getName() + POSTFIX_SELECTMAP, map);  
	 }  
	}  
	 
	/** 
	 * sql 查询. 
	 *  
	 * @param sql 
	 *            直接sql的语句(需要防止注入式攻击) 
	 * @throws SQLException  
	 */  
	public List<T> find(Class<T> entityClass, String sql) throws SQLException {  
	 Assert.hasText(sql);  
	 if (StringUtils.isEmpty(sql))  
	  return this.getSqlMapClient().queryForList(entityClass.getName() + POSTFIX_SELECTBYID, null);  
	 else  
	  return this.getSqlMapClient()  
	    .queryForList(entityClass.getName() + POSTFIX_SELECTSQL, sql);  
	}  
	 
	/** 
	 * 根据属性名和属性值查询对象. 
	 *  
	 * @return 符合条件的对象列表 
	 * @throws SQLException  
	 */  
	public List<T> findBy(Class<T> entityClass, String name, Object value) throws SQLException {  
	 Assert.hasText(name);  
	 Map<String, Object> map = new HashMap<String, Object>();  
	 map.put(name, value);  
	 return find(entityClass, map);  
	}  
	 
	/** 
	 * 根据属性名和属性值查询对象. 
	 *  
	 * @return 符合条件的唯一对象 
	 */  
	public T findUniqueBy(Class<T> entityClass, String name, Object value) {  
	 Assert.hasText(name);  
	 Map<String, Object> map = new HashMap<String, Object>();  
	 try {  
	  PropertyUtils.getProperty(entityClass.newInstance(), name);  
	  map.put(name, value);  
	  map.put("findUniqueBy", "True");  
	  return (T) getSqlMapClient().queryForObject(entityClass.getName() + POSTFIX_SELECTMAP,  
	    map);  
	 } catch (Exception e) {  
	  logger.error("Error when propertie on entity," + e.getMessage(), e.getCause());  
	  return null;  
	 }  
	 
	}  
	 
	/** 
	 * 根据属性名和属性值以Like AnyWhere方式查询对象. 
	 * @throws SQLException  
	 */  
	public List<T> findByLike(Class<T> entityClass, String name, String value) throws SQLException {  
	 Assert.hasText(name);  
	 Map<String, Object> map = new HashMap<String, Object>();  
	 map.put(name, value);  
	 map.put("findLikeBy", "True");  
	 return getSqlMapClient().queryForList(entityClass.getName() + POSTFIX_SELECTMAP, map);  
	 
	}  
	 
	/** 
	 * 判断对象某些属性的值在数据库中不存在重复 
	 *  
	 * @param tableName 
	 *            数据表名字 
	 * @param names 
	 *            在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password" <br> 
	 *            FIXME how about in different schema? 
	 */  
	public boolean isNotUnique(Object entity, String tableName, String names) {  
	 try {  
	  String primarykey;  
	  Connection con = getSqlMapClient().getCurrentConnection();  
	  ResultSet dbMetaData = con.getMetaData().getPrimaryKeys(con.getCatalog(), null, tableName);  
	  dbMetaData.next();  
	  if (dbMetaData.getRow() > 0) {  
	   primarykey = dbMetaData.getString(4);  
	   if (names.indexOf(primarykey) > -1)  
	    return false;  
	  } else {  
	   return true;  
	  }  
	 
	 } catch (SQLException e) {  
	  logger.error(e.getMessage(), e);  
	  return false;  
	 }  
	 return false;  
	}  
	 
	/** 
	 * 分页查询函数，使用PaginatedList. 
	 *  
	 * @param pageNo 
	 *            页号,从0开始. 
	 * @throws SQLException 
	 */  
	@SuppressWarnings("unchecked")  
	public Page<T,PK> pagedQuery(String sqlName, HashMap<String, Object> hashMap, Integer pageNo, Integer pageSize)  
	  throws SQLException {  
	 
	 if (pageNo == null || pageSize == null) {  
	  List list = getSqlMapClient().queryForList(sqlName, hashMap);  
	  if (list == null || list.size() == 0) {  
	   return new Page<T,PK>();  
	  } else {  
	   return new Page<T,PK>(0, list.size(), list.size(), list);  
	  }  
	 } else {  
	  Assert.hasText(sqlName);  
	  Assert.isTrue(pageNo >= 1, "pageNo should start from 1");  
	  // Count查询  
	  Integer totalCount = (Integer) getSqlMapClient().queryForObject(sqlName + ".Count", hashMap);  
	 
	  if (totalCount < 1) {  
	   return new Page<T,PK>();  
	  }  
	 
	  // 实际查询返回分页对象  
	  int startIndex = Page.getStartOfPage(pageNo, pageSize);  
	  hashMap.put("startIndex", startIndex);  
	  hashMap.put("pageSize", pageSize);  
	  List list = getSqlMapClient().queryForList(sqlName, hashMap);  
	 
	  return new Page<T,PK>(startIndex, totalCount, pageSize, list);  
	 }  
	}  
	 
	public Page<T, PK> pagedQuery(String sqlName, String[] properties,
			Object[] propertyValues, Integer pageNo, Integer pageSize) throws Exception {
		// TODO Auto-generated method stub
		Map<String, Object> map = new HashMap<String, Object>();  
	    for (int i = 0; i < properties.length; i++) {  
	        map.put(properties[i], propertyValues[i]);  
	    }
		return this.pagedQuery(sqlName, (HashMap)map, pageNo, pageSize);
	}
	
	public String getMappedSQL(String sqlName) {  
	 String sql = null;  
	 
	 SqlMapClientImpl sqlmap = (SqlMapClientImpl) getSqlMapClient();  
	 
	 MappedStatement stmt = sqlmap.getMappedStatement(sqlName);  
	 StaticSql staticSql = (StaticSql) stmt.getSql();  
	 sql = staticSql.getSql(null, null);  
	 return sql;  
	}  
	public Integer count(Class<T> entityClass, String propertyName, Object propertyValue) throws Exception, SQLException {  
	         return count(entityClass, new String[]{propertyName},new Object[]{propertyValue});  
	     }  
	   
	public Integer count(Class<T> entityClass, String[] propertyNames, Object[] propertyValues) throws Exception, SQLException {  
		Map<String, Object> map = new HashMap<String, Object>();  
		for (int i = 0; i < propertyNames.length; i++) {  
			map.put(propertyNames[i], propertyValues[i]);  
        }  
		return (Integer) getSqlMapClient().queryForObject(entityClass.getName() + POSTFIX_COUNT, map);  
	}  
		   
    public Integer countLikeByMap(Class<T> entityClass,String[] propertyNames, Object[] propertyValues) throws Exception, SQLException {  
         Map<String, Object> map = new HashMap<String, Object>();  
         for (int i = 0; i < propertyNames.length; i++) {  
             map.put(propertyNames[i], propertyValues[i]);  
        }  
         return (Integer) getSqlMapClient().queryForObject(entityClass.getName() + POSTFIX_COUNTLIKEBYMAP, map);  
     }
    /** 根据ID及条件删除对象 */  
    public void deleteByIdsMap(Class<T> entityClass, List<PK> ids, String[] properties, Object[] propertyValues) throws Exception {  
        Map<String, Object> map = new HashMap<String, Object>();  
        for (int i = 0; i < properties.length; i++) {  
            map.put(properties[i], propertyValues[i]);  
        }  
        map.put("ids", ids);  
        getSqlMapClient().delete(entityClass.getName() + POSTFIX_DELETEBYIDSMAP, map);  
    }  
       
    /** 
     * 根据条件删除对象 
     */  
    public int deleteByMap(Class<T> entityClass, String[] properties, Object[] propertyValues) throws Exception {  
       
        Map<String, Object> map = new HashMap<String, Object>();  
        for (int i = 0; i < properties.length; i++) {  
            map.put(properties[i], propertyValues[i]);  
        }  
        return getSqlMapClient().delete(entityClass.getName() + POSTFIX_DELETEBYMAP, map);  
    }
    
    /** 
    #      * 更新对象的部分属性 
    #      */  
    public int update(Class<T> entityClass, PK id, String[] properties, Object[] propertyValues) throws Exception {  
        // 更新数据库  
        Map<String, Object> map = new HashMap<String, Object>();  
        for (int i = 0; i < properties.length; i++) {  
            map.put(properties[i], propertyValues[i]);  
        }  
        map.put("id", id);  
        return getSqlMapClient().update(entityClass.getName() + POSTFIX_UPDATEBYMAP, map);  
    }  
       
    /** 
     * 根据ID列表更新对象的部分属性 
     */  
    public int updateByIdsMap(Class<T> entityClass, List<PK> ids,String[] properties, Object[] propertyValues) throws Exception{  
        // 更新数据库  
        Map<String, Object> map = new HashMap<String, Object>();  
        for (int i = 0; i < properties.length; i++) {  
            map.put(properties[i], propertyValues[i]);  
        }  
        map.put("ids", ids);  
        return getSqlMapClient().update(entityClass.getName() + POSTFIX_UPDATEBYIDSMAP, map);  
    }
}
